package com.guimin.demo.api.admin;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.guimin.demo.constant.ServiceConstant;
import com.guimin.demo.dto.AddServiceDto;
import com.guimin.demo.dto.UpdateCommunityServiceDto;
import com.guimin.demo.entity.CommunityService;
import com.guimin.demo.service.CommunityServiceService;
import com.guimin.demo.vo.ServiceVo;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.statement.update.Update;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 桂民社区服务信息表(GuiminService)表控制层
 *
 * @author makejava
 * @since 2021-11-01 15:32:25
 */
@Slf4j
@RestController
@RequestMapping("/admin/service")
public class CommunityServiceApi {
    /**
     * 服务对象
     */
    @Resource
    private CommunityServiceService serviceService;

    /**
     * 获取
     *
     * @return r
     */
    @GetMapping("/get/list")
    public R<IPage<ServiceVo>> getServiceList(@RequestParam(defaultValue = "1") Long current,
                                              @RequestParam(defaultValue = "10") Long size) {
        IPage<CommunityService> page = serviceService.page(new Page<>(current, size), new LambdaQueryWrapper<CommunityService>()
                .ne(CommunityService::getState, 2)
        );
        Page<ServiceVo> vo = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        vo.setRecords(new ArrayList<>(page.getRecords().size()));
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (CommunityService one : page.getRecords()) {
            ServiceVo o = new ServiceVo()
                    .setId(String.valueOf(one.getId()))
                    .setParentId(one.getParentId() == null ? "0" : String.valueOf(one.getParentId()))
                    .setName(one.getName())
                    .setOpen("1".equals(one.getState()) ? "true" : "")
                    .setType(String.valueOf(one.getType()))
                    .setPrice(one.getPrice() == null ? null : one.getPrice().toString())
                    .setCreateDatetime(one.getCreateDatetime() == null ? null : sdf.format(one.getCreateDatetime()));
            vo.getRecords().add(o);
        }
        return R.ok(vo);
    }

    /**
     * 添加分类或服务
     *
     * @param dto 数据
     * @return r
     */
    @PostMapping("/add")
    public R<String> addService(@RequestBody @Validated AddServiceDto dto) {
        if (ServiceConstant.Type.CLASSIFY.value.equals(dto.getType())) {
            dto.setPrice(null);
        } else if (!ServiceConstant.Type.SERVOCE.value.equals(dto.getType())) {
            return R.failed("参数“type”错误");
        }
        if (dto.getParentId() != 0 &&
                1 != serviceService.count(new LambdaQueryWrapper<CommunityService>()
                        .eq(CommunityService::getId, dto.getParentId()))
        ) {
            return R.failed("父节点不存在");
        }
        CommunityService service = new CommunityService()
                .setParentId(dto.getParentId() == 0 ? null : dto.getParentId())
                .setName(dto.getName())
                .setType(dto.getType())
                .setPrice(dto.getPrice())
                .setCreateDatetime(new Date())
                .setState(ServiceConstant.State.CLOSE.value);
        boolean save = serviceService.save(service);
        return save ? R.ok(null) : R.failed("保存失败");
    }

    /**
     * 开启或关闭服务
     *
     * @param id     服务id
     * @param isOpen 是否开启
     * @return r
     */
    @PutMapping("/setup/state")
    public R<String> openOrClose(@RequestParam Integer id, @RequestParam Boolean isOpen) {
        log.info("=====================\n" + "id=" + id + ",isOpen=" + isOpen);
        List<CommunityService> list = serviceService.list(new LambdaQueryWrapper<CommunityService>()
                .select(CommunityService::getId, CommunityService::getParentId, CommunityService::getState)
        );
        LambdaQueryWrapper<CommunityService> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CommunityService::getId, id);
        getPrevOrNextByIsOpen(id, list, isOpen, wrapper);
        boolean update = serviceService.update(
                new CommunityService()
                        .setState(isOpen ? ServiceConstant.State.OPEN.value : ServiceConstant.State.CLOSE.value),
                wrapper
        );
        return update ? R.ok(null) : R.failed("保存失败");
    }

    /**
     * 遍历节点，以便找出需要关闭或开启的节点
     * 1.某个节点开启时（isOpen=true），传入其父节点节点唯一id，并向上找出其所有上级节点，逐一开启（isOpen=true）；
     * 2.某个节点关闭时（isOpen=false），传入该节点唯一id，并向下找出其所有下级节点，逐一关闭（isOpen=false）；
     * 注：该方法只负责找出所有上级节点或所有下级节点，开启或关闭的节点本身需要自行添加。
     *
     * @param id      节点id
     * @param list    所有节点
     * @param isOpen  是否开启
     * @param wrapper SQL代码生成器
     */
    private void getPrevOrNextByIsOpen(int id, List<CommunityService> list, boolean isOpen, LambdaQueryWrapper<CommunityService> wrapper) {
        for (CommunityService service : list) {
            int parentId = service.getParentId() == null ? 0 : service.getParentId();
            if (isOpen && id == service.getId()) {
                //向上开启节点
                if (ServiceConstant.State.OPEN.value.equals(service.getState())) {
                    //如果节点本身在开启中，跳过
                    continue;
                }
                wrapper.or().eq(CommunityService::getId, service.getId());
                //向上级查找
                if (parentId != 0) {
                    getPrevOrNextByIsOpen(parentId, list, true, wrapper);
                }
                //因为父级节点只有一个，所以只运行一遍
                break;
            } else if (!isOpen && id == parentId) {
                //向下关闭节点
                if (ServiceConstant.State.CLOSE.value.equals(service.getState())) {
                    //如果节点本身在关闭中，跳过
                    continue;
                }
                wrapper.or().eq(CommunityService::getId, service.getId());
                //如果有下级节点
                getPrevOrNextByIsOpen(service.getId(), list, false, wrapper);
            }
        }
    }

    /**
     * 修改社区服务
     * @param dto 修改数据
     * @return r
     */
    @PutMapping("/update")
    public R<String> updateCommunityService(@RequestBody @Validated UpdateCommunityServiceDto dto) {

        boolean update = serviceService.update(new CommunityService()
//                .setType(null)
                        .setName(dto.getName())
//                .setParentId(null)
                        .setPrice(dto.getPrice())
//                .setState("")
                        .setUpdateDatetime(new Date()),
                new LambdaQueryWrapper<CommunityService>()
                        .eq(CommunityService::getId, dto.getId())
        );
        return update ? R.ok(null) : R.failed("修改失败");
    }

    /**
     * 删除社区服务
     * @param serviceId 服务id
     * @return  r
     */
    @DeleteMapping("/delete")
    public R<String> deleteCommunityServiceById(@RequestParam Integer serviceId) {
        boolean remove = serviceService.removeById(serviceId);
        return remove ? R.ok(null) : R.failed("");
    }

}

